
#pragma unmanaged
#include <Liberty3D/Library/TaskScheduler.h>
#include <Liberty3D/Library/Task.h>
#pragma managed

#include <windows.h>
#include <msclr/lock.h>

static bool initialized = false;

using namespace Liberty::Engine;
using namespace Liberty::Library;
using namespace System::Collections::Generic;
using namespace System::Threading;

namespace Liberty { namespace Library {
    ref class TaskSchedulerInfo : public System::Object {
    public:
        static Thread^ mainThread;

    public:
        static void PoolTask(System::Object^ state) {
            if (!TaskScheduler::pooling()) {
                System::Threading::ThreadPool::QueueUserWorkItem(gcnew WaitCallback(TaskSchedulerInfo::PoolTask));
            }
        }
    };
}}

void TaskScheduler::consoleInit() {
    if (!initialized) {
        initialized = true;

        init();
        TaskSchedulerInfo::mainThread = Thread::CurrentThread;
    }
}

bool TaskScheduler::isMainThread() {
    return TaskSchedulerInfo::mainThread == Thread::CurrentThread;
}

void TaskScheduler::scheduleImpl(const std::shared_ptr<Task>& task) {
    if (!task->mustExecuteOnMainThread()) {
        System::Threading::ThreadPool::QueueUserWorkItem(gcnew WaitCallback(TaskSchedulerInfo::PoolTask));
    }
}

#pragma unmanaged

bool TaskScheduler::consoleLoop(bool autoStopWhenNoTask) {
    _running = true;
    
    while (_running) {
        std::shared_ptr<Task> taskToRun(dequeue(true));
        
        if (taskToRun) {
            taskToRun->execute();
            finished(taskToRun);
        }
        else {
            if (autoStopWhenNoTask) {
                if (!waitForPendingTasks()) {
                    break;
                }
                else {
                    continue;
                }
            }
            
            waitForPendingTasks();
        }
    }
    
    triggerTaskEvent();
    
    {
        boost::mutex::scoped_lock guard(_mutex);
        
        _running = false;
        
        while (_runningTasks.size() > 0) {
            waitForTaskEvent(guard);
        }
    }
    
    return true;
}

void TaskScheduler::consoleStop() {
    _running = false;
}

void TaskScheduler::cancelImpl(const std::shared_ptr<Task>& task) {
}

unsigned int Liberty::Library::TaskScheduler::numProcessors() {
    SYSTEM_INFO sysinfo;

    GetSystemInfo(&sysinfo);
    return sysinfo.dwNumberOfProcessors;
}
